/*
	Written By Sanjay Giri
	
	Copyright (C) 2011 Prads Projects
	Please read COPYING.txt included along with this source code for more detail.
	If not included, see http://www.gnu.org/licenses/
*/

#include "libDisassembler.h"

//converts int to string
//example: 64, "64"
string Disassembler::intToString(unsigned int n){
	stringstream num;
	num << n;
	return num.str();
}

//converts int to hex string with 0x symbol
//example: 15, "0xf"
string Disassembler::intToHexString(unsigned int i){
	stringstream ss;
	ss << "0x" << hex << i;
	return ss.str();
}

//converts int to hex string but without 0x symbol
//example: 10, "a"
string Disassembler::intToHexNum(unsigned int i) {
	stringstream ss;
	ss << hex << i;
	return ss.str();
}


//Given the memory and address, it disassembles the code in that location
//example: 10 12 00 00, "MOV R2, R1"
string Disassembler::disassemble(unsigned char *cMem, int addr){

	unsigned char opcode = cMem[addr];
	unsigned int regX = cMem[addr+1] & 0x0f;
	unsigned int regY = cMem[addr+1] >> 4;
	unsigned int regZ = cMem[addr+2] & 0x0f;
	unsigned int hhll = (cMem[addr+3] <<8 ) | cMem[addr + 2];

	switch (opcode) {
		case 0x00:
			return "NOP";
			break;
		case 0x01:
			return "CLS";
			break;
		case 0x02:
			return "VBLNK";
			break;
		case 0x03:
			{
				unsigned int n=cMem[addr+2];
				return "BGC "+intToHexString(n);
			}
			break;
		case 0x04:
			return "SPR "+intToHexString(hhll);
			break;
		case 0x05:
			return "DRW R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+intToHexString(hhll);
			break;
		case 0x06:
			return "DRW R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x07:
			return "RND R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x08:
			{
				unsigned int num=cMem[addr+3]&0x0f;
				
				if(num==0){
					return "FLIP 0, 0";
				}else if(num==1){
					return "FLIP 0, 1";
				}else if(num==2){
					return "FLIP 1, 0";
				}else if(num==3){
					return "FLIP 1, 1";
				}
			}
			break;
		case 0x09:
			//SND0();	
			break;
		case 0x0A:
			//SND1HHLL();
			break;
		case 0x0B:
			//SND2HHLL();
			break;
		case 0x0C:
			//SND3HHLL();
			break;
		case 0x0D:
			//SNPRxHHLL();
			break;
		case 0x0E:
			//SNGADVTSR();
			break;
		case 0x10:
			return "JMP "+intToHexString(hhll);
			break;
		case 0x12:
			return "J"+intToHexNum(regX)+" "+intToHexString(hhll);
			break;
		case 0x13:
			return "JME R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+intToHexString(hhll);
			break;
		case 0x16:
			return "JMP R"+intToHexNum(regX);
			break;
		case 0x14:
			return "CALL "+intToHexString(hhll);
			break;
		case 0x15:
			return "RET";
			break;
		case 0x17:
			return "C"+intToHexNum(regX)+" "+intToHexString(hhll);
			break;
		case 0x18:
			return "CALL R"+intToHexNum(regX);
			break;
		case 0x20:
			return "LDI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x21:
			return "LDI SP, "+intToHexString(hhll);
			break;
		case 0x22:
			return "LDM R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x23:
			return "LDM R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x24:
			return "MOV R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x30:
			return "STM R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x31:
			return "STM R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x40:
			return "ADDI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x41:
			return "ADD R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x42:
			return "ADD R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x50:
			return "SUBI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x51:
			return "SUB R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x52:
			return "SUB R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x53:
			return "CMPI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x54:
			return "CMP R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x60:
			return "ANDI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x61:
			return "AND R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x62:
			return "AND R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x63:
			return "TSTI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x64:
			return "TST R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x70:
			return "ORI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x71:
			return "OR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x72:
			return "OR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x80:
			return "XORI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x81:
			return "XOR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x82:
			return "XOR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0x90:
			return "MULI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0x91:
			return "MUL R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0x92:
			return "MUL R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0xA0:
			return "DIVI R"+intToHexNum(regX)+", "+intToHexString(hhll);
			break;
		case 0xA1:
			return "DIV R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0xA2:
			return "DIV R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY)+", "+"R"+intToHexNum(regZ);
			break;
		case 0xB0:
			return "SHL R"+intToHexNum(regX)+", "+intToString(regZ);
			break;
		case 0xB1:
			return "SHR R"+intToHexNum(regX)+", "+intToString(regZ);
			break;
		case 0xB2:
			return "SAR R"+intToHexNum(regX)+", "+intToString(regZ);
			break;
		case 0xB3:
			return "SHL R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0xB4:
			return "SHR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0xB5:
			return "SAR R"+intToHexNum(regX)+", "+"R"+intToHexNum(regY);
			break;
		case 0xC0:
			return "PUSH R"+intToHexNum(regX);
			break;
		case 0xC1:
			return "POP R"+intToHexNum(regX);
			break;
		case 0xC2:
			return "PUSHALL";
			break;
		case 0xC3:
			return "POPALL";	
			break;
		case 0xC4:
			return "PUSHF";
			break;
		case 0xC5:
			return "POPF";
			break;
		case 0xD0:
			return "PAL "+intToHexString(hhll);
			break;
		case 0xD1:
			return "PAL R"+intToHexNum(regX);
			break;
	}

	return "Undifined: " + intToHexNum(cMem[addr]) + " " + intToHexNum(cMem[addr + 1]) + " " 
		+ intToHexNum(cMem[addr + 2]) + " " + intToHexNum(cMem[addr + 3]);

}
